﻿using ChartingModel.Collections;
using ChartingModel.Collections.Series;
using ChartingModel.Style;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Printing;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WpfChartingControlLibrary.Common;

namespace WpfChartingControlLibrary.BarCharts
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:WpfChartingControlLibrary.BarCharts"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:WpfChartingControlLibrary.BarCharts;assembly=WpfChartingControlLibrary.BarCharts"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:BarChartControl11/>
    ///
    /// </summary>
    /// 
    
    [TemplatePart(Name = "PART_legendCanvas", Type = typeof(Canvas))]
    [TemplatePart(Name = "PART_ChartCanvas", Type = typeof(Canvas))]
    [TemplatePart(Name = "PART_TextCanvas", Type = typeof(Canvas))]
    [TemplatePart(Name = "PART_ChartGrid", Type = typeof(Grid))]
    [TemplatePart(Name = "PART_YLabelTextBlock", Type = typeof(FrameworkElement))]
    [TemplatePart(Name = "PART_XLabelTextBlock", Type = typeof(FrameworkElement))]
    [TemplatePart(Name = "PART_TitleTextBlock", Type = typeof(FrameworkElement))]
    public partial class BarChartControl : System.Windows.Controls.Control, IWeakEventListener
    {

        public static DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(BarChartControl), new PropertyMetadata(new PropertyChangedCallback(ShowValueLabelsChanged)));

        public static DependencyProperty XAxisTitleProperty = DependencyProperty.Register("XAxisTitle", typeof(string), typeof(BarChartControl), new PropertyMetadata(new PropertyChangedCallback(ShowValueLabelsChanged)));

        public static DependencyProperty YAxisTitleProperty = DependencyProperty.Register("YAxisTitle", typeof(string), typeof(BarChartControl), new PropertyMetadata(new PropertyChangedCallback(ShowValueLabelsChanged)));

        public static DependencyProperty DataSeriesBarProperty = DependencyProperty.Register("DataSeriesBar", typeof(DataSeriesBar), typeof(BarChartControl));

        public static DependencyProperty DataCollectionProperty = DependencyProperty.Register("DataCollection", typeof(BarChartDataList), typeof(BarChartControl));

        public static DependencyProperty ValueLabelsShowProperty = DependencyProperty.Register("ShowValueLabels", typeof(Visibility), typeof(BarChartControl), new PropertyMetadata(new PropertyChangedCallback(ShowValueLabelsChanged)));

        public static DependencyProperty ValueLabelsMinFontSizeProperty = DependencyProperty.Register("ValueLabelsMinFontSize", typeof(double), typeof(BarChartControl), new PropertyMetadata(new PropertyChangedCallback(ShowValueLabelsChanged)));

        public static DependencyProperty ShowValueToolTipProperty = DependencyProperty.Register("ShowValueToolTip", typeof(bool), typeof(BarChartControl), new PropertyMetadata(new PropertyChangedCallback(ShowValueLabelsChanged)));

        public static DependencyProperty ChartStyleProperty = DependencyProperty.Register("ChartStyle", typeof(ChartStyleGridLines), typeof(BarChartControl));

        static BarChartControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(BarChartControl), new FrameworkPropertyMetadata(typeof(BarChartControl)));
            CommandManager.RegisterClassCommandBinding(typeof(BarChartControl), new CommandBinding(ApplicationCommands.Print, PrintCommand_Executed));
        }


        /// <summary>
        /// set focus to the graph control so printing command is activated from ctrl+P
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);
            if (this.IsEnabled && !this.IsFocused)
            {
                this.Focus();
            }
        }

        /// <summary>
        /// used to print the graph
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void PrintCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            BarChartControl barChart = sender as BarChartControl;
            PrintDialog printDlg = new System.Windows.Controls.PrintDialog();

            if (printDlg.ShowDialog() == true)
            {

                try
                {
                    //get the size of the printer page 
                    PrintCapabilities capabilities = printDlg.PrintQueue.GetPrintCapabilities(printDlg.PrintTicket);
                    double pageMargin = Math.Min(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight);
                    double additionalMargin = Math.Max(0, pageMargin + 5);
                    Size pageSize = new Size(capabilities.PageImageableArea.ExtentWidth - additionalMargin * 2, capabilities.PageImageableArea.ExtentHeight - additionalMargin * 2);
                    //get scale of the print wrt to screen of WPF visual 
                    double scale = Math.Min(pageSize.Width / barChart.ActualWidth, pageSize.Height / barChart.ActualHeight);
                    Size printSize = new Size(barChart.ActualWidth * scale, barChart.ActualHeight * scale);
                    Point upperLeft = new Point(capabilities.PageImageableArea.OriginWidth + additionalMargin, capabilities.PageImageableArea.OriginHeight + additionalMargin);
                    //Transform the Visual to scale 
                    barChart.LayoutTransform = new ScaleTransform(scale, scale); barChart.Measure(printSize); barChart.Arrange(new Rect(upperLeft, printSize));
                    printDlg.PrintVisual(barChart, "Test");
                }
                catch (System.Printing.PrintQueueException)
                {

                }catch(System.Printing.PrintSystemException)
                { }

                barChart.LayoutTransform = null;





               // //get selected printer capabilities
               // System.Printing.PrintCapabilities capabilities = printDlg.PrintQueue.GetPrintCapabilities(printDlg.PrintTicket);

               // //get scale of the print wrt to screen of WPF visual
               // double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / barChart.ActualWidth,
               //     capabilities.PageImageableArea.ExtentHeight / barChart.ActualHeight);

               // //Transform the Visual to scale
               //barChart.LayoutTransform = new ScaleTransform(scale, scale);

               // //get the size of the printer page
               // Size sz = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
               // //Capture the image of the visual in the same size as Printing page.


               // RenderTargetBitmap bmp = new RenderTargetBitmap((int)barChart.ActualWidth, (int)barChart.ActualHeight, 96, 96, PixelFormats.Pbgra32);
               // bmp.Render(barChart);

               // //create new visual which would be initialized by image
               // DrawingVisual vis = new DrawingVisual();

               // //get printer origin point help with formatting
               // Point originPoint = new Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight);

                
               // //create a drawing context so that image can be rendered to print
               // DrawingContext dc = vis.RenderOpen();

               // dc.DrawImage(bmp, new System.Windows.Rect(originPoint, sz));
               // dc.Close();

               // //now print the image visual to printer to fit on the one page.
               // printDlg.PrintVisual(vis, "Image Fit to Page WPF Print");
               // barChart.LayoutTransform = null;
            
            }






            //PrintDialog printDialog = new PrintDialog();
            //if (printDialog.ShowDialog() == true)
            //{
            //    //get selected printer capabilities
            //    System.Printing.PrintCapabilities capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);

            //    //get scale of the print wrt to screen of WPF visual
            //    double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / barChart.ActualWidth, capabilities.PageImageableArea.ExtentHeight / barChart.ActualHeight);

            //    //Transform the Visual to scale
            //    barChart.LayoutTransform = new ScaleTransform(scale, scale);


            //    //get the size of the printer page

            //    Size sz = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);

            //    //update the layout of the visual to the printer page size.

            //    barChart.Measure(sz);

            //    barChart.Arrange(new Rect(new Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));

            //    //now print the visual to printer to fit on the one page.

            //    printDialog.PrintVisual(barChart, "First Fit to Page WPF Print");

            //    barChart.LayoutTransform = null;
            //}
        }
      
        public BarChartControl()
        {
            this.DataCollection = new BarChartDataList();
            this.DataSeriesBar = new DataSeriesBar(this.ChartStyle);
            this.ChartStyle = new ChartStyleGridLines();
        }

        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public string XAxisTitle
        {
            get { return (string)GetValue(XAxisTitleProperty); }
            set { SetValue(XAxisTitleProperty, value); }
        }

        public string YAxisTitle
        {
            get { return (string)GetValue(YAxisTitleProperty); }
            set { SetValue(YAxisTitleProperty, value); }
        }

        public BarChartDataList DataCollection
        {
            get { return (BarChartDataList)GetValue(DataCollectionProperty); }
            set { SetValue(DataCollectionProperty, value); }
        }

        public DataSeriesBar DataSeriesBar
        {
            get { return (DataSeriesBar)GetValue(DataSeriesBarProperty); }
            set { SetValue(DataSeriesBarProperty, value); }
        }

        public ChartStyleGridLines ChartStyle
        {
            get { return (ChartStyleGridLines)GetValue(ChartStyleProperty); }
            set { SetValue(ChartStyleProperty, value); }
        }

        public Visibility ShowValueLabels
        {
            get { return (Visibility)GetValue(ValueLabelsShowProperty); }
            set { SetValue(ValueLabelsShowProperty, value); }
        }

        public double ValueLabelsMinFontSize
        {
            get { return (double)GetValue(ValueLabelsMinFontSizeProperty); }
            set { SetValue(ValueLabelsMinFontSizeProperty, value); }
        }

        public bool ShowValueToolTip
        {
            get { return (bool)GetValue(ShowValueToolTipProperty); }
            set { SetValue(ShowValueToolTipProperty, value); }
        }

        private static void ShowValueLabelsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            BarChartControl bcc = (BarChartControl)sender;
            if (e.Property == ValueLabelsShowProperty)
                bcc.DataCollection.LabelValuesVisibility = (Visibility)e.NewValue;
            if (e.Property == ShowValueToolTipProperty)
                bcc.DataCollection.ActiveToolTip = (bool)e.NewValue;
            if (e.Property == ValueLabelsMinFontSizeProperty)
                bcc.DataCollection.LabelMinimumFontSize = (double)e.NewValue;
        }

        public void AddChart()
        {
            _chartCanvas.Children.Clear();
            _textCanvas.Children.RemoveRange(1, _textCanvas.Children.Count - 1);

            this.ChartStyle.AddChartStyle(true, true);
            if (this.DataCollection.DataList.Count != 0)
            {
                this.DataCollection.AddBars(this.ChartStyle);
            }
        }

        Canvas _chartCanvas;
        Canvas _textCanvas;
        Grid _chartGrid;

        ListBox lb;
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _chartCanvas = GetTemplateChild("PART_ChartCanvas") as Canvas;
            _textCanvas = GetTemplateChild("PART_TextCanvas") as Canvas;
            _chartGrid = GetTemplateChild("PART_ChartGrid") as Grid;
            lb = GetTemplateChild("lb") as ListBox;
            this.ChartStyle.ChartCanvas = _chartCanvas; ;
            this.ChartStyle.TextCanvas = _textCanvas;
            GridSizeChangedEventManager.AddListener(_chartGrid, this);
        }

        public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            if (managerType == typeof(GridSizeChangedEventManager))
            {
                GridSizeChanged(_chartGrid, (SizeChangedEventArgs)e);
            }
            else
            {
                return false;       // unrecognized event
            }
            return true;
        }

        public void GridSizeChanged(object sender, SizeChangedEventArgs e)
        {
            _textCanvas.Width = _chartGrid.ActualWidth;
            if (_chartGrid.ActualHeight > SystemParameters.HorizontalScrollBarHeight)
            {
                _textCanvas.Height = _chartGrid.ActualHeight - SystemParameters.HorizontalScrollBarHeight;
            }
            else
            {
                _textCanvas.Height = _chartGrid.ActualHeight; 
            }
            AddChart();
    //        lb.Width = _chartGrid.ActualWidth;
    //        lb.Height = _chartGrid.ActualHeight;
        }

        public void GridSizeSet()
        {
            _textCanvas.Width = _chartGrid.ActualWidth;
            _textCanvas.Height = _chartGrid.ActualHeight;

            _chartCanvas.Children.Clear();
            _textCanvas.Children.RemoveRange(1, _textCanvas.Children.Count - 1);
            AddChart();

        }

        public void GridSizeSet(double width, double height)
        {
            _textCanvas.Width = width;
            _textCanvas.Height = height;
            _chartCanvas.Children.Clear();
            _textCanvas.Children.RemoveRange(1, _textCanvas.Children.Count - 1);
            AddChart();

        }

    }

}
